package edu.wpi.cs509.ui;

import java.awt.*;


/**
 * This layout manager defines the Stratego layout for the GameWindowFrame.
 * 
 * The layout is the following:
 * 
 * +------------------------------------+-----------------+
 * |                                    |                 | 
 * |                                    |                 | 
 * |                                    |    Graveyard    | 
 * |                                    |                 | 
 * |                                    |                 | 
 * |                                    |                 | 
 * |                                    +-----------------+ 
 * |           GameBoardPanel           |    Controls     | 
 * |                                    |                 | 
 * |                                    +-----------------+
 * |                                    |                 | 
 * |                                    |                 | 
 * |                                    |    Graveyard    | 
 * |                                    |                 | 
 * |                                    |                 | 
 * |                                    |                 | 
 * +------------------------------------+-----------------+
 * 
 * @author afoltan
 *
 */
public class GameWindowFrameLayout implements LayoutManager {

	static final int GAP = 8;
	
    private int minWidth = 0, minHeight = 0;
    private int preferredWidth = 0, preferredHeight = 0;
    private double preferredAspectRatio;
    
	private GameBoardPanel gameboard;
	private Graveyard topGraveyard;
	private Graveyard bottomGraveyard;
	private GameWindowControls controls;
 
	private boolean preferredSet = false;
	
	private Dimension parentWindow = new Dimension(400,400);
	
    public GameWindowFrameLayout( GameBoardPanel gameboard, 
    		Graveyard topGraveyard, Graveyard bottomGraveyard, GameWindowControls controls ) {
        this.gameboard = gameboard;
        this.topGraveyard = topGraveyard;
        this.bottomGraveyard = bottomGraveyard;
        this.controls = controls;

    }
  
    /**
     * Determine the preferred size of the game window
     * @param parent
     */
    private void setPreferredSize( Container parent ) {
        
        Dimension boardDim, g1Dim, g2Dim, ctrlDim;
        
        Insets insets = parent.getInsets();
        
        //Reset preferred/minimum width and height.
        preferredWidth = insets.left + insets.right;
        preferredHeight = insets.top + insets.bottom;
 
        boardDim = gameboard.getPreferredSize();
    	g1Dim = topGraveyard.getPreferredSize(); 
    	g2Dim = bottomGraveyard.getPreferredSize(); 
    	ctrlDim = controls.getPreferredSize(); 
        
    	// Calculate the overall preferred width based on individual components
        preferredWidth += boardDim.width;
        preferredWidth += GAP;
        preferredWidth += Math.max(g1Dim.width, ctrlDim.width);
        
        // Calculate the overall preferred height based on individual components
        preferredHeight += Math.max(boardDim.height, 
        		(g1Dim.height+ctrlDim.height+g2Dim.height));
        
        // init the parent window size to start with preferred size
        parentWindow.width = preferredWidth;
        parentWindow.height = preferredHeight;
        
        // For now, don't go smaller than this
        minWidth = preferredWidth / 2;
        minHeight = preferredHeight / 2;
        
        // calculate some important ratios
        preferredAspectRatio = (double)preferredWidth / (double)preferredHeight;
        
        // System.out.println("PreferredAspectRatio="+preferredAspectRatio);
        
    }

    /* Required by LayoutManager. */
    public void addLayoutComponent(String name, Component comp) {
    }
 
    /* Required by LayoutManager. */
    public void removeLayoutComponent(Component comp) {
    } 
 
    /* Required by LayoutManager. */
    public Dimension preferredLayoutSize(Container parent) {
        Dimension dim = new Dimension(0, 0);
  
        if (!preferredSet) setPreferredSize(parent);
        
        //Always add the container's insets!
        Insets insets = parent.getInsets();
        dim.width = preferredWidth
                    + insets.left + insets.right;
        dim.height = preferredHeight
                     + insets.top + insets.bottom;
  
        return dim;
    }
 
    /* Required by LayoutManager. */
    public Dimension minimumLayoutSize(Container parent) {
        Dimension dim = new Dimension(0, 0);
 
        if (!preferredSet) setPreferredSize(parent);

        //Always add the container's insets!
        Insets insets = parent.getInsets();
        dim.width = minWidth
                    + insets.left + insets.right;
        dim.height = minHeight
                     + insets.top + insets.bottom;
 
        return dim;
    }
 
    /**
     * Forces the parent container to maintain a useful aspect ratio 
     * @param parent - the parent container
     * @return double - the scale factor to apply to the preferred sizes for this
     * new parent container
     */
    private double forceParentAspectRatio( Container parent, int usableWidth, int usableHeight ) {
    	
    	if (usableHeight < minHeight) {
    		usableHeight = minHeight;
    	}
    	
    	// System.out.println("parent=("+parent.getWidth()+","+parent.getHeight()+")");
    	
    	// maintain aspect ratio at all times
    	usableWidth = (int) ((double)usableHeight * preferredAspectRatio);
    	
    	// System.out.println("new=("+usableWidth+","+usableHeight+")");
    	
        // update the desired parent window size
        parentWindow.width = usableWidth;
        parentWindow.height = usableHeight;

    	parent.setSize(usableWidth, usableHeight);
    	
    	double scaleFactor = ((double)usableWidth/(double)preferredWidth);
    	return scaleFactor;
    }
    
    /* Required by LayoutManager. */
    /*
     * This is called when the panel is first displayed,
     * and every time its size changes.
     * Note: You CAN'T assume preferredLayoutSize or
     * minimumLayoutSize will be called -- in the case
     * of applets, at least, they probably won't be.
     */
    public void layoutContainer(Container parent) {
    	
        if (!preferredSet) setPreferredSize(parent);

        Insets insets = parent.getInsets();
        int usableWidth = parent.getWidth()
                       - (insets.left + insets.right);
        int usableHeight = parent.getHeight()
                        - (insets.top + insets.bottom);
        
        double scaleFactor = forceParentAspectRatio(parent,usableWidth,usableHeight);

        // System.out.println("scale="+scaleFactor);
        
        Dimension boardResize = new Dimension();
        boardResize.setSize( (int)((double)gameboard.getPreferredSize().width*scaleFactor), 
        					 (int)((double)gameboard.getPreferredSize().height*scaleFactor) );
        
        Dimension topGraveyardResize = new Dimension();
        topGraveyardResize.setSize( (int)((double)topGraveyard.getPreferredSize().width*scaleFactor), 
        							(int)((double)topGraveyard.getPreferredSize().height*scaleFactor) );

        Dimension bottomGraveyardResize = new Dimension();
        bottomGraveyardResize.setSize( (int)((double)bottomGraveyard.getPreferredSize().width*scaleFactor), 
        							   (int)((double)bottomGraveyard.getPreferredSize().height*scaleFactor) );

        Dimension controlsResize = new Dimension();
        controlsResize.setSize( (int)((double)controls.getPreferredSize().width*scaleFactor),
        						controls.getPreferredSize().height );
            	
        // Set the components size and position.
        int x = insets.left;
        int y = insets.top;
        
        gameboard.setBounds(x, y, boardResize.width, boardResize.height);
        
        x += boardResize.width + GAP;
        topGraveyard.setBounds(x, y, topGraveyardResize.width, topGraveyardResize.height);
        
        y += topGraveyardResize.height;
        controls.setBounds(x, y, controlsResize.width, controlsResize.height);
        
        y += controlsResize.height;
        bottomGraveyard.setBounds(x, y, bottomGraveyardResize.width, bottomGraveyardResize.height);
        
    }
 
    public String toString() {
        return "GameWindowFrameLayout";
    }
    
    public Dimension getGameWindowSize() {
    	return parentWindow;
    }
    
    public void setNewOpponentGraveyard( Graveyard newG ) {
    	Rectangle r = topGraveyard.getBounds();
    	newG.setBounds(r);
    	topGraveyard = newG;
    }
}
